<!-- BMS控制 -->
<template>
  <div class="app-container">
    <div class="bmsTop">
      <el-radio-group v-model="radio1">
        <el-radio-button label="控制" value="控制" />
        <el-radio-button label="设置" value="设置" @click="setup()" />
      </el-radio-group>
      <el-input
        placeholder="请输入内容"
        v-model="queryParams.deviceCode"
        style="width: 150px; margin-left: 30px"
      />
      <el-button type="primary" style="margin-left: 5px" @click="handleQuery">
        搜索
      </el-button>
      <el-button
        type="success"
        style="margin-left: 5px"
        @click="downloadPointUpload"
      >
        读取
      </el-button>

      <div style="margin-left: 35px">
        设备IMEI号: {{ deviceItem.deviceCode }}
      </div>
      <div style="margin-left: 35px">
        设备编号(BT码): {{ deviceItem.towerNumber }}
      </div>
      <div
        style="margin-left: 25px"
        :style="deviceItem.onlineStatus == 'ONLINE' ? 'color:#67C23A;' : ''"
      >
        {{ deviceItem.onlineStatus == "ONLINE" ? "设备在线" : "设备离线" }}
      </div>
      <div style="margin-left: 25px">更新时间: {{ device_update_time }}</div>
      <!-- <div class="historicalCurve" @click="hostableshow = true">历史曲线</div> -->
      <div class="historicalCurve" @click="kasaysayan">历史数据</div>
    </div>
    <div class="elmain" v-show="radio1 == '控制'">
      <div class="main_lft">
        <div class="socCurVEchartWarp warp">
          <div class="bigBatteryWarp">
            <div class="status_box">
              <div class="bat_icon Idle">
                <div
                  class="soc_status"
                  :style="'width:' + deviceData.SOC + '%'"
                ></div>
                <div class="num">
                  <span class="font-24">soc:</span>
                  <span class="font-28 bold mg-l-5 percentage">
                    {{ deviceData.SOC }}%
                  </span>
                </div>
              </div>
            </div>
            <div class="battertContentWarp">
              <div>
                电池状态:
                <span>闲置</span>
              </div>
              <div>
                SOH:
                <span>{{ deviceData.SOH }} %</span>
              </div>
              <div>
                循环次数:
                <span>{{ deviceData.cycleTimes }} 次</span>
              </div>
            </div>
          </div>
          <div class="echartsBox" id="echartsBoxs"></div>
        </div>
        <div class="StatuAndParamWarp">
          <div class="statuWarp warp">
            <div class="titleMolde">
              {{
                Parameter[0].pointGroupName
                  ? Parameter[0].pointGroupName
                  : "参数"
              }}
              <!-- <div style="font-size: 14px; color: #d9d9d9; cursor: pointer;" @click="dialogTableVisibleTest = true">
                测试
              </div> -->
              <div
                style="font-size: 14px; color: #d9d9d9; cursor: pointer"
                @click="dialogTableVisible = true"
              >
                更多>>
              </div>
            </div>
            <div class="contentBox">
              <template
                v-for="(item, index) in Parameter[0].headers"
                :key="index"
              >
                <div class="statusBox">
                  <div class="row">
                    <span>{{ item.name }}</span>
                    <span class="font-warn">
                      {{ item.data }} {{ item.unit }}
                    </span>
                  </div>
                </div>
              </template>
            </div>
          </div>
          <div class="paramWarp warp">
            <div class="titleMolde">
              {{
                Property[0].pointGroupName
                  ? Property[0].pointGroupName
                  : "BMS参数配置"
              }}
              <div
                style="font-size: 14px; color: #d9d9d9"
                @click="dialogTableVisible2 = true"
              >
                更多>>
              </div>
            </div>

            <div class="contentBox">
              <template
                v-for="(item, index) in Property[0].headers"
                :key="index"
              >
                <div class="row row100">
                  <span class="config-item-w130 color-white">
                    {{ item.name }}
                  </span>
                  <span class="config-item-w80 mrg-lf-10 font-bluesky">
                    {{ item.data }}{{ item.unit }}
                  </span>
                </div>
              </template>
            </div>
          </div>
        </div>
      </div>
      <div class="main_rit warp">
        <div id="Timeline" style="height: 100%"></div>
      </div>
    </div>
    <div class="bmsBottom" v-show="radio1 == '控制'">
      <div class="smallBatterysWarp warp">
        <div class="titleMolde">
          {{ Parameter[1].pointGroupName }}
          <el-popover
            placement="top"
            popper-style="background-color:#fff;"
            :width="200"
            trigger="click"
          >
            <template #reference>
              <el-icon style="cursor: pointer">
                <QuestionFilled />
              </el-icon>
            </template>
            <div class="softStatusColorInfo ColorInfo1">
              :
              <i></i>
              最高电压
            </div>
            <div class="softStatusColorInfo ColorInfo2">
              :
              <i></i>
              最低电压
            </div>
            <!-- <div class="softStatusColorInfo ColorInfo3">
              :
              <i></i>
              均衡中
            </div> -->
            <div class="softStatusColorInfo ColorInfo4">
              :
              <i></i>
              正常
            </div>
          </el-popover>
        </div>
        <div class="smallBatteryContent">
          <template v-for="(item, index) in Parameter[1].headers" :key="index">
            <div
              class="battery-item"
              :class="
                item.isMax === true
                  ? 'batteryStatuundefined2'
                  : item.isMin === true
                    ? 'batteryStatuundefined1'
                    : 'batteryStatuundefined'
              "
              style=""
              v-if="item.name != '电池个数'"
            >
              <p class="battery-label">
                <span class="label-index">#{{ index }}</span>
                <span class="volt">{{ item.data }} {{ item.unit }}</span>
              </p>
            </div>
          </template>
        </div>
      </div>
      <div class="warnWarp warp">
        <div class="titleMolde">
          报警状态
          <el-popover
            :width="450"
            placement="top"
            popper-style="background-color:#fff;"
            trigger="click"
          >
            <template #reference>
              <span style="cursor: pointer; font-size: 14px; color: #999">
                报警统计>>
              </span>
            </template>
            <ul class="warnWarpUl">
              <li
                v-if="alarmlist.statistics"
                v-for="item in alarmlist.statistics"
              >
                {{ item.name }}: {{ item.count }}次
              </li>
              <!-- <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li>
              <li>单体过压次数: 0次</li> -->
              <li v-else>暂无数据</li>
            </ul>
          </el-popover>
        </div>

        <div class="contentBox" v-if="alarmlist.data?.length >= 1">
          <div v-for="item in alarmlist.data">{{ item.alarmName }}</div>
        </div>
        <div class="noAlarm" v-else>暂无告警</div>
      </div>
      <div class="boxMap">
        <div class="address">中国</div>
        <div id="trajectoryMap" style="width: 100%; height: 100%"></div>
      </div>
    </div>
    <el-dialog
      v-model="dialogTableVisible"
      class="dialogTableVisibleclass"
      :title="
        Parameter[0].pointGroupName ? Parameter[0].pointGroupName : '参数'
      "
      width="800"
    >
      <div class="titleMolde dialog">{{ Parameter[0].pointGroupName }}</div>
      <ul class="dialogUl">
        <li :key="index" v-for="(item, index) in Parameter[0].headers">
          {{ index + 1 }}、 {{ item.name }}: {{ item.data }}
        </li>
      </ul>
    </el-dialog>
    <el-dialog
      v-model="dialogTableVisibleTest"
      class="dialogTableVisibleclass"
      :title="
        Parameter[0].pointGroupName ? Parameter[0].pointGroupName : '参数'
      "
      width="90vw"
    >
      <div class="titleMolde dialog">{{ Parameter[0].pointGroupName }}</div>
      <ul class="dialogUlTO fontColor_333">
        <li :key="index" v-for="(item, index) in testdata">
          {{ item.name }}:
          <el-select
            v-model="item.type"
            placeholder="Select"
            style="width: 80px"
          >
            <el-option
              v-for="item in options"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <el-input v-model="item.data" style="width: 180px; color: #000" />
        </li>
      </ul>
      <span style="color: #000">
        {{ HEXT }}
      </span>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="yesSave">确定</el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog
      v-model="dialogTableVisible2"
      class="dialogTableVisibleclass"
      title="BMS的状态信息"
      width="800"
    >
      <template v-for="(item, index) in Property" :key="index">
        <div class="titleMolde dialog">{{ item.pointGroupName }}</div>
        <ul class="dialogUl">
          <li v-for="(val, idx) in item.headers" :key="idx">
            {{ val.name }}: {{ val.data }} {{ val.unit }}
          </li>
        </ul>
      </template>
    </el-dialog>
    <el-dialog
      v-model="hostableshow"
      @close="closedata()"
      :title="hosvisible == 1 ? '历史数据' : '历史曲线'"
      width="1300"
    >
      <div class="block" style="">
        <span style="color: #000">日期：</span>
        <el-date-picker
          v-model="value1"
          type="daterange"
          range-separator="至"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
          value-format="YYYY-MM-DD hh:mm:ss"
        />

        <el-select
          v-model="hosqueryParams.pointGroupId"
          placeholder="Select"
          style="width: 240px; margin-left: 10px"
        >
          <el-option
            v-for="item in pointGroupList"
            :key="item.pointGroupId"
            :label="item.pointGroupName"
            :value="item.pointGroupId"
          />
        </el-select>
        <!-- pointGroupList -->
        <el-button
          type="primary"
          style="margin-left: 10px"
          @click="changehos(hosvisible === 1 ? 0 : 1)"
        >
          {{ hosvisible == 0 ? "历史数据" : "历史曲线" }}
        </el-button>
      </div>
      <div v-if="hosvisible === 1" style="margin-top: 20px">
        <el-table ref="multipleTable" scrollbar-always-on :data="todaytable">
          <el-table-column type="selection" align="center" v-if="todayhead" />
          <el-table-column
            width="180"
            v-for="(item, index) in todayhead"
            :key="index"
            :label="item.name"
            :property="item.pointCode"
            align="center"
          />
        </el-table>
        <pagination
          @pagination="handleQuery"
          v-if="hosqueryParams.pages.total > 0"
          v-model:total="hosqueryParams.pages.total"
          v-model:page="hosqueryParams.pages.current"
          v-model:limit="hosqueryParams.pages.size"
        />
      </div>
      <div v-else class="main_rit3" style="margin-top: 20px">
        <div id="Timeline3" style="height: 500px; width: 1300px"></div>
      </div>
      <div style="text-align: center; margin: 20px">
        <el-button type="primary" @click="dataSubmit(hosvisible === 1 ? 0 : 1)">
          查询
        </el-button>
        <el-button @click="closedata()">关闭</el-button>
      </div>
    </el-dialog>

    <div v-if="radio1 == '设置'" style="height: calc(100% - 42px)">
      <deviceSetup :ld="deviceld" />
    </div>
  </div>
</template>

<script setup lang="ts">
defineOptions({
  name: "Bmscontrol",
  inheritAttrs: false,
});
import deviceSetup from "@/views/setup/index.vue";
import { useRoute, useRouter } from "vue-router";
import * as echarts from "echarts";
import BmscontrolApi, {
  controlBMS,
  detectionBMS,
  parameter,
  curveOfTheDayOV,
  parameterData,
  DeviceHistoricalDataParams,
} from "@/api/bmscontrol";
import LocationApi, { Locations } from "@/api/location";
import downloadApi from "@/api/download";
import pointGroupApi from "@/api/pointGroup";

import deviceAlarmApi, { DeviceAlarmlist } from "@/api/deviceAlarm";
import DeviceApi, { deviceVOData } from "@/api/device";
import { initMap } from "@/common/map";
import { SingleToHex } from "./SingleToHex";
import { times, addition, minus, divide, round } from "@/assets/digit";
import { useMqtt } from "@/utils/mqttService";
import { useUserStore } from "@/store";

const { client, subscribe } = useMqtt(
  "jizhi" +
    useUserStore().user.id +
    "_" +
    localStorage.getItem("TOKEN_KEYExpiration"),
  "jizhi",
  "jizhi@!#123456"
);
let topic = ref(
  "jziot/v1/platform/1839273075284299778/1847517267932360706/point/reply"
);
client.on("message", (topic, message) => {
  console.log(`收到消息: ${message.toString()} 主题: ${topic}`);
});

/**
@date: 2024-10-24 16:20:11
订阅消息
*/
const subscribeToTopic = () => {
  subscribe(topic.value);
};

let _AMap: any = null;
let _map: any = null;
let radio1 = ref("控制");
const chart: Ref<echarts.ECharts | null> = ref(null);
const timeline: Ref<echarts.ECharts | null> = ref(null);
const timeline3: Ref<echarts.ECharts | null> = ref(null);
let dialogTableVisible = ref(false);
let dialogTableVisibleTest = ref(false);
let dialogTableVisible2 = ref(false);
let deviceSN = ref("BT12345");
const router = useRouter();
const route = useRoute();
let setParamList = reactive<detectionBMS[]>([]);
let curveOfThe = reactive<curveOfTheDayOV>({
  deviceCode: "",
  endTime: undefined,
  startTime: undefined,
});
let locadata = reactive<Locations>({
  x: "",
  y: "",
});
let alarmlist = ref<DeviceAlarmlist>({
  statistics: [
    {
      name: "",
      count: 0,
    },
  ],
  data: [],
});
let deviceld = ref<any>("");

let hosvisible = ref(1);
let hostableshow = ref(false);
const today = new Date();
today.setHours(0, 0, 0, 0);
// 格式化日期为 YYYY-MM-DD hh:mm:ss
function formatDate(date: any) {
  const year = date.getFullYear();
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
  const day = date.getDate().toString().padStart(2, "0");
  const hours = date.getHours().toString().padStart(2, "0");
  const minutes = date.getMinutes().toString().padStart(2, "0");
  const seconds = date.getSeconds().toString().padStart(2, "0");

  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 获取明天的零点时间
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1); // 明天的日期

const todayFormatted = formatDate(today);
const tomorrowFormatted = formatDate(tomorrow);

let value1 = ref([todayFormatted, tomorrowFormatted]);
console.log("今天的零点时间:", todayFormatted); // 今天的 00:00:00
console.log("明天的零点时间:", tomorrowFormatted); // 明天的 00:00:00

const deviceData = {
  SOC: "0" as string | undefined,
  SOH: "0" as string | undefined,
  cycleTimes: "0" as string | undefined,
  V: 0 as number | undefined,
  A: 0 as number | undefined,
  W: 0 as number | undefined,
};
let device_update_time = "";
let options = [
  {
    value: "number",
    label: "数字",
  },
  {
    value: "string",
    label: "字符",
  },
  {
    value: "IEEE",
    label: "数子有小数",
  },
];

let HEXT = ref("");

let testdata = ref<parameterData[]>([
  {
    name: "总电压",
    type: "number",
    fileId: "100",
    data: "100.0",
    unit: "V",
  },
]);
let Parameter = reactive<parameter[]>([
  {
    pointGroupId: "",
    pointGroupName: "",
    lastUpdateTime: "",
    headers: [
      {
        name: "",
        fileId: "",
        data: "",
        unit: "",
        isMax: false,
        isMin: false,
      },
    ],
  },
  {
    pointGroupId: "",
    pointGroupName: "",
    lastUpdateTime: "",
    headers: [
      {
        name: "",
        fileId: "",
        data: "",
        unit: "",
      },
    ],
  },
]);
let Property = reactive<parameter[]>([
  {
    pointGroupId: "",
    pointGroupName: "",
    lastUpdateTime: "",
    headers: [
      {
        name: "",
        fileId: "",
        data: "",
        unit: "",
      },
    ],
  },
  {
    pointGroupId: "",
    pointGroupName: "",
    lastUpdateTime: "",
    headers: [
      {
        name: "",
        fileId: "",
        data: "",
        unit: "",
      },
    ],
  },
]);
function Setup() {
  router.push({ path: "/setup", query: { deviceSN: "123456" } });
}
if (route.query.deviceSN) {
  deviceSN.value = route.query.deviceSN as string;
}
let hosqueryParams = reactive<DeviceHistoricalDataParams>({
  pages: {
    current: 1,
    size: 10,
    startTime: "",
    endTime: "",
    total: 0,
    orders: [
      {
        column: "",
        asc: true,
      },
    ],
  },
  deviceId: "",
  pointGroupId: "",
});

function changehos(type: number) {
  hosvisible.value = type;
  if (type == 1) {
    setTimeout(() => {
      dataSubmit(0);
    }, 100);
  } else {
    setTimeout(() => {
      dataSubmit(1);
    }, 200);
  }
}
let pointGroupList = ref<any>([]);
function getParameterPointGroupInfo() {
  pointGroupApi.getParameterPointGroupInfo(deviceld.value).then((res) => {
    hosqueryParams.pointGroupId = res[0].pointGroupId;
    pointGroupList.value = res;
  });
}
function kasaysayan() {
  hostableshow.value = true;
  changehos(1);
}
function dataSubmit(type: number) {
  if (curveOfThe.deviceCode !== "") {
    if (value1.value.length !== 0) {
      if (type == 0) {
        hosqueryParams.deviceId = deviceld.value;
        hosqueryParams.pages.endTime = value1.value[1];
        hosqueryParams.pages.startTime = value1.value[0];
        BmscontrolApi.deviceHistoricalData(hosqueryParams).then((resdata) => {
          todaytable.value = resdata.data.dataList;
          todayhead.value = resdata.headers;
          console.log(todaytable.value);
          console.log(todayhead.value);

          // hosvisible.value = false

          hostableshow.value = true;
        });
      } else {
        curveOfThe.startTime = value1.value[0]; // 获取时间戳（毫秒）
        curveOfThe.endTime = value1.value[1]; // 获取时间戳（毫秒）
        todaysCurve3();
        timeline3.value = markRaw(
          echarts.init(document.getElementById("Timeline3") as HTMLDivElement)
        );
      }
    } else {
      ElMessage({
        message: "请先选择日期范围",
        type: "error",
      });
    }
  } else {
    ElMessage({
      message: "请先选择设备",
      type: "error",
    });
  }
  // }
}
// 切换设置页面
function setup() {
  console.log(deviceld.value, "deviceld.value");

  if (deviceld.value == "") {
    ElMessage({
      message: "请先查询要设置的设备",
      type: "success",
    });
  }
}
function closedata() {
  if (timeline3.value) {
    timeline3.value.dispose();
  }
  // value1.value = ''
  hostableshow.value = false;
  // hosvisible.value = false
}
let deviceItem = ref<deviceVOData>({
  deviceCode: "",
  deviceName: "",
  towerNumber: "",
  deviceTypeCode: "",
  onlineStatus: "ONLINE",
});
async function setMap() {
  const { AMap, map } = await initMap("trajectoryMap");
  _AMap = AMap;
  _map = map;
  if (locadata.x) {
    // const userCoordinates = {
    //     x: locadata.x, // Longitude
    //     y: locadata.y   // Latitude
    //   };

    // 定位到指定位置并放大
    const targetLocation = new AMap.LngLat(locadata.x, locadata.y);
    map.setZoomAndCenter(
      12,
      [targetLocation.lng, targetLocation.lat],
      false,
      500
    );

    // map.setCenter(targetLocation); // 设置地图中心为指定位置
    // map.setZoom(13); // 设置地图缩放级别（可以根据需要调整）

    // 创建标记实例
    const marker = new AMap.Marker({
      position: targetLocation,
      title: "目标位置", // 可选：为标记添加标题
      icon: "//api.jz-iot.net/uploads/default/BmMarker1.png",
    });
    // 将标记添加到地图
    marker.setMap(map);

    marker.on("click", () => {
      // 跳转页面
      router.push({
        path: "/location/bms",
        query: { deviceID: deviceld.value },
      });
      // , query: { deviceSN: windowData.basicInfo.deviceCode }
    });
  }
}
let queryParams = reactive<controlBMS>({
  deviceCode: deviceSN.value,
  // "pointGroupIdList": ['1831283140610306049', '1831283110256128001', '1831519877047611393'],
});

/** 设置图表  */
const setChartOptions = () => {
  if (!chart.value) {
    return;
  }
  let cdata = [
    { name: "电压(V)", data: deviceData.V },
    { name: "电流(A)", data: deviceData.A },
    { name: "功率(kW)", data: deviceData.W },
  ];
  let centerArr = [
    ["17%", "45%"],
    ["50%", "45%"],
    ["83%", "45%"],
  ];
  let titleArr: any = [];
  let seriesArr: any = [];
  var linearColor = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
    {
      offset: 0,
      color: "#00E1FD", // 0% 处的颜色
    },
    {
      offset: 1,
      color: "#419FFE", // 100% 处的颜色
    },
  ]);
  cdata.forEach((item, index) => {
    titleArr.push({
      text: item.name,
      bottom: "0%",
      left: centerArr[index][0],
      textAlign: "center",
      textStyle: {
        color: "#fff",
        fontSize: 18,
      },
    });
    seriesArr.push({
      name: item.name,
      max: 500,
      type: "gauge",
      splitNumber: 3,
      radius: "80%",
      center: centerArr[index],
      progress: {
        show: true,
        width: 5,
        itemStyle: {
          // 属性lineStyle控制线条样式
          color: linearColor,
        },
      },
      axisLine: {
        // 坐标轴线
        lineStyle: {
          // 属性lineStyle控制线条样式
          width: 5,
        },
      },
      axisLabel: {
        show: false,
      },
      axisTick: {
        show: true,
        splitNumber: 5,
        lineStyle: {
          color: "#419FFE", //用颜色渐变函数不起作用
          width: 2,
        },
        length: 10,
      },
      splitLine: {
        show: false,
      },
      title: {
        show: false,
      },
      detail: {
        fontSize: 16,
        fontWeight: "bold",
        color: "#00E1FD",
        offsetCenter: [0, "60%"],
        valueAnimation: true,
        formatter: "{value}",
      },
      pointer: {},
      data: [
        {
          value: item.data,
        },
      ],
    });
  });
  let option = {
    title: titleArr,
    series: seriesArr,
  };
  console.log(seriesArr);

  chart.value.setOption(option);
};
/**
@date: 2024-08-17 11:03:47
复制数据
*/
function clickCopy(msg: number[]) {
  const formattedMsg = msg.join("\n");
  const save = function (e: any) {
    e.clipboardData.setData("text/plain", formattedMsg);
    e.preventDefault(); // 阻止默认行为
  };
  const once = {
    once: true,
  };
  document.addEventListener("copy", save, once); // 添加一个copy事件,当触发时执行一次,执行完删除
  document.execCommand("copy"); // 执行copy方法
  ElMessage({
    message: "复制成功",
    type: "success",
  });
}
/** 设置图表  */
const setChartOptions3 = (data: any) => {
  if (!timeline3.value) {
    return;
  }
  data.headerList.forEach((item: any) => {
    item["type"] = "line";
  });
  let option = {
    tooltip: {
      trigger: "axis",
    },
    title: {
      left: "left",
      text: "当日曲线",
      textStyle: {
        color: "#fff",
      },
      top: "2%",
    },
    legend: {
      top: "2%",
      padding: [5, 40, 0, 120],
      type: "scroll",
      pageIconColor: "#fff",
      pageTextStyle: {
        color: "#ededed",
      },
      textStyle: {
        color: "#fff",
        rich: {
          a: {
            width: 60,
            height: 12,
            backgroundColor: "transparent", // 一定要设置，不然不生效
            padding: [0, 20, 0, 0],
          },
        },
      },
      formatter: (params: string) => {
        return `{a|${params}}`;
      },
    },
    xAxis: {
      type: "category",
      boundaryGap: false,
      axisLine: {
        show: true,
        lineStyle: {
          color: "#fff",
        },
      },
      data: data.time,
    },
    yAxis: {
      type: "value",
      boundaryGap: [0, "100%"],
      axisLine: {
        show: true,
        lineStyle: {
          color: "#fff",
        },
      },
      splitLine: {
        show: true,
        lineStyle: {
          color: "rgba(105, 105, 105, 1)",
        },
      },
    },
    dataZoom: [
      {
        type: "inside",
        start: 0,
        end: 20,
      },
      {
        start: 0,
        end: 20,
      },
    ],
    series: data.headerList,
  };
  timeline3.value.setOption(option);
};
function generateTimeSlots() {
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());

  const timeSlots = [];
  const slotDuration = 2 * 60 * 60 * 1000; // 2小时，单位是毫秒

  for (let i = 0; i < 5; i++) {
    const slotStart = new Date(today.getTime() + i * slotDuration);

    timeSlots.push(slotStart.toISOString());
  }

  return timeSlots;
}

const setChartOptions2 = (data: any) => {
  if (!timeline.value) {
    return;
  }
  console.log(data, 6666);

  data.headerList.forEach((item: any) => {
    item["type"] = "line";
  });
  if (data.time.length === 0) {
    data.time = generateTimeSlots();
    data.headerList = [
      {
        name: "总电压",
        type: "line",
        data: [0, 0, 0, 0, 0, 0, 0],
      },
      {
        name: "总电流",
        type: "line",
        data: [0, 0, 0, 0, 0, 0, 0],
      },
      {
        name: "SOC",
        type: "line",
        data: [0, 0, 0, 0, 0, 0, 0],
      },
    ];
  }
  let option = {
    tooltip: {
      trigger: "axis",
    },
    title: {
      left: "left",
      text: "当日曲线",
      textStyle: {
        color: "#fff",
      },
      top: "2%",
    },
    legend: {
      top: "2%",
      padding: [5, 40, 0, 120],
      textStyle: {
        color: "#fff",
        rich: {
          a: {
            width: 60,
            height: 12,
            backgroundColor: "transparent", // 一定要设置，不然不生效
            padding: [0, 20, 0, 0],
          },
        },
      },
      formatter: (params: string) => {
        return `{a|${params}}`;
      },
    },
    xAxis: {
      type: "category",
      boundaryGap: false,
      axisLine: {
        show: true,
        lineStyle: {
          color: "#FFFFFF",
        },
      },
      data: data.time,
    },
    yAxis: {
      type: "value",
      boundaryGap: [0, "100%"],
      axisLine: {
        show: true,
        lineStyle: {
          color: "#FFFFFF",
        },
      },
      splitLine: {
        show: true,
        lineStyle: {
          color: "rgba(105, 105, 105, 1)",
        },
      },
    },
    dataZoom: [
      {
        type: "inside",
        start: 0,
        end: 20,
      },
      {
        start: 0,
        end: 20,
      },
    ],
    series: data.headerList,
  };

  timeline.value.setOption(option);
};
// 判断电芯最大值和最小值
function findMax(arr: any) {
  if (arr.length === 0) return null; // 检查数组是否为空

  // 初始化最大值和最小值
  let maxValue = arr[0].data;
  let minValue = arr[1].data;

  // 第一次遍历：找到最大值和最小值
  arr.forEach((item: any, idx: number) => {
    if (idx === 0) {
      return; // 跳过索引为 0 的元素
    }
    if (item.data > maxValue) {
      maxValue = item.data; // 更新最大值
    }
    if (item.data < minValue) {
      minValue = item.data; // 更新最小值
    }
  });

  // 第二次遍历：为所有最大值和最小值对象添加标识
  arr.forEach((item: any) => {
    if (item.data === maxValue) {
      item.isMax = true; // 添加最大值标识
    }
    if (item.data === minValue) {
      item.isMin = true; // 添加最小值标识
    }
  });
  console.log(arr, "值");

  return arr; // 返回修改后的原数组
}
/** 查询 */
function bmsDetails() {
  BmscontrolApi.detection(queryParams)
    .then((data) => {
      setParamList = data;

      Object.assign(Parameter, data[0].data);
      Object.assign(Property, data[1].data);
      const maxValue = findMax(Parameter[1].headers);
      Parameter[1].headers = maxValue;
      testdata.value = Parameter[1].headers;
      testdata.value = testdata.value.map((item: any) => {
        item = { ...item, type: "number" };
        return item;
      });
      deviceData.SOC = Parameter[0].headers[2].data;
      deviceData.SOH = Parameter[0].headers[11].data;
      deviceData.cycleTimes = Parameter[0].headers[15].data;

      if (typeof Parameter[0].headers[0].data === "string") {
        deviceData.A = Number(Parameter[0].headers[1].data);
        deviceData.V = Number(Parameter[0].headers[0].data);
        deviceData.W = parseFloat(
          Math.abs(times(deviceData.A, deviceData.V)).toFixed(3)
        );
      }
      Parameter.forEach((item) => {
        if (
          item.hasOwnProperty("lastUpdateTime") &&
          item.lastUpdateTime !== null
        ) {
          if (item.lastUpdateTime > device_update_time) {
            device_update_time = item.lastUpdateTime;
          } else if (device_update_time == "") {
            console.log(item.lastUpdateTime);
          }
        }
      });
      setChartOptions();
    })
    .finally(() => {});
}
// 获取定位
function getloc() {
  // let data={
  // 	deviceld:curveOfThe.deviceCode
  // }
  LocationApi.getDeviceLocationInfo(deviceld.value).then((datas) => {
    locadata = datas.locationInfo.location;
    setMap();
  });
}
function todaydata() {
  let data = {
    deviceId: deviceld.value,
  };
  deviceAlarmApi.getDeviceAlarm(data).then((datas) => {
    console.log(datas, "000");
    alarmlist.value = datas;
  });
}
/** 查询 */
function handleQuery() {
  DeviceApi.selectByCode(queryParams.deviceCode)
    .then((data) => {
      if (radio1.value == "控制") {
        ElMessage.success("查询成功");
        deviceSN.value = data.deviceCode;
        deviceld.value = data.id;
        curveOfThe.deviceCode = data.deviceCode;
        // Object.assign(deviceItem, { ...data })
        deviceItem.value = data;
        todaysCurve();
        todaydata();
        bmsDetails();
        getloc();

        topic.value = `jziot/v1/platform/${deviceItem.value.deviceTypeCode}/${deviceItem.value.deviceCode}/point/reply`;
        subscribeToTopic();
      } else {
        deviceld.value = data.id;
      }
      getParameterPointGroupInfo();
    })
    .finally(() => {});
}

function todaysCurve() {
  BmscontrolApi.curveOfTheDay(curveOfThe)
    .then((data) => {
      setChartOptions2(data);
    })
    .finally(() => {});
}

let todaytable = ref();
interface todaytype {
  name: string;
  pointCode: string;
}
let todayhead = ref<todaytype[]>();
function todaysCurve3() {
  BmscontrolApi.curveOfTheDay(curveOfThe)
    .then((data) => {
      setChartOptions3(data);
    })
    .finally(() => {});
}

onMounted(() => {
  /** 初始化图表1  */

  chart.value = markRaw(
    echarts.init(document.getElementById("echartsBoxs") as HTMLDivElement)
  );
  timeline.value = markRaw(
    echarts.init(document.getElementById("Timeline") as HTMLDivElement)
  );

  setChartOptions();
  window.addEventListener("resize", handleResize);

  if (route.query.deviceSN !== "" || route.query.deviceSN !== undefined) {
    handleQuery();
  }
});
function yesSave() {
  var header = "77ff";
  var finish = "ff77";
  var data = "";
  var lengt = "";
  var lengths = 0;
  testdata.value.forEach((val) => {
    /**
      信号量
    */
    var a = parseInt(val.fileId).toString(16).padStart(4, "0");
    /**
        属性值
        */
    var c;
    /**
    属性值长度
    */
    var b;
    if (val.data) {
      if (val.type === "number") {
        if (isAllDigits(val.data)) {
          lengths++;
          c = padWithZeroIfOddLength(parseInt(val.data).toString(16));
          b = (c.length / 2).toString(16).padStart(4, "0");
          console.log(a, b, c);
          data += a + b + c;
        }
      } else if (val.type === "string") {
        lengths++;
        c = strToHexCharCode(val.data);
        b = (c.length / 2).toString(16).padStart(4, "0");
        data += a + b + c;
      } else if (val.type === "IEEE") {
        lengths++;

        c = SingleToHex(val.data);
        b = (c.length / 2).toString(16).padStart(4, "0");
        data += a + b + c;
      }
    }
  });
  const secondsTimestamp = Math.floor(Date.now() / 1000);
  data =
    lengths.toString(16).padStart(2, "0") +
    data +
    secondsTimestamp.toString(16).padStart(8, "0");
  lengt = (data.length / 2).toString(16).padStart(4, "0");
  HEXT.value = (header + lengt + data + finish).toUpperCase();
  console.log("hex", HEXT.value);
}
//ASCII码转16进制
function strToHexCharCode(str: string) {
  if (str === "") {
    return "";
  } else {
    var hexCharCode = [];
    //hexCharCode.push("0x");
    for (var i = 0; i < str.length; i++) {
      hexCharCode.push(str.charCodeAt(i).toString(16));
    }
    return hexCharCode.join("");
  }
}
function isAllDigits(str: string) {
  // 使用正则表达式检查字符串
  const regex = /^-?\d+(\.\d+)?$/;
  return regex.test(str);
}
function padWithZeroIfOddLength(str: string) {
  // 检查字符串的长度
  if (str.length % 2 === 1) {
    // 如果长度为单数，则在前面补零
    return "0" + str;
  }
  // 如果长度为偶数，返回原字符串
  return str;
}
const downloadPointUpload = useThrottleFn(() => {
  let data = {
    deviceId: deviceItem.value.id as string,
    pointGroupTypeFlag: radio1.value == "控制" ? "PARAMETER" : "PROPERTY",
  };
  downloadApi.downloadPointUpload(data).then((download) => {
    console.log(download);
    setTimeout(() => {
      handleQuery();
    }, 3000);
  });
}, 3010);
/** 窗口大小变化时，重置图表大小 */
const handleResize = () => {
  setTimeout(() => {
    if (chart.value) {
      chart.value.resize();
    }
    if (timeline.value) {
      timeline.value.resize();
    }
    if (timeline3.value) {
      timeline3.value.resize();
    }
  }, 100);
};
</script>
<style lang="scss" scoped>
@use "@/styles/util" as *;

.app-container {
  height: calc(100vh - 120px);
  box-sizing: border-box;
  padding-bottom: 10px;
  overflow: hidden;
}

// 复用样式
.warp {
  color: #fff;
  background: #1c1c1c;
  border-radius: 5px;
  padding: 0 10px;
}

.titleMolde {
  font-weight: bold;
  position: relative;
  display: flex;
  padding-left: 15px;
  justify-content: space-between;
  margin: 6px 0 4px;
  align-items: center;

  &::after {
    content: "";
    width: 8px;
    height: 8px;
    position: absolute;
    left: 4px;
    top: 6px;
    background: #2cdfe5b5;
  }

  &::before {
    content: "";
    width: 8px;
    height: 8px;
    background: #09e0e7;
    position: absolute;
    left: 0;
    top: 2px;
  }

  &.dialog {
    color: #67c23a;

    &::after {
      content: "";
      width: 8px;
      height: 8px;
      position: absolute;
      left: 4px;
      top: 6px;
      background: #66c039b3;
    }

    &::before {
      content: "";
      width: 8px;
      height: 8px;
      background: #67c23a;
      position: absolute;
      left: 0;
      top: 2px;
    }
  }
}

.font-warn {
  color: #bec045;
}

.font-bluesky {
  color: #2ec7c9;
}

.row {
  padding: 5px 5px;
  background: #2d2d2d;
  border-radius: 3px;
  margin-bottom: 10px;
  display: flex;
  justify-content: space-between;
  font-size: 14px;
}

.bmsTop {
  display: flex;
  align-items: center;
  position: relative;
  margin-bottom: 10px;
  width: 100%;

  .historicalCurve {
    position: absolute;
    right: 30px;
    border: 1px solid #ccc;
    padding: 3px 10px;
    border-radius: 6px;
    cursor: pointer;
  }
}

.elmain {
  width: 100%;
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;

  .main_lft {
    width: 57%;
    display: flex;
    flex-wrap: wrap;

    .socCurVEchartWarp {
      width: 100%;
      // height: 140px;
      height: calc(100% - 370px);
      display: flex;

      .bigBatteryWarp {
        width: 50%;
        display: flex;
        align-items: center;
        height: 140px;

        .battertContentWarp {
          div {
            margin: 10px 0;
            font-size: vw(17);

            span {
              color: #2ec7c9;
            }
          }
        }

        .status_box {
          display: flex;
          justify-content: center;
          margin: 0 45px;

          .bat_icon {
            position: relative;
            width: vw(180);
            height: vh(100);
            border: 3px solid #2ec7c9;
            border-radius: 4px;
            padding: 2px;
            box-sizing: border-box;

            &::after {
              content: "";
              display: block;
              position: absolute;
              width: vw(12);
              height: vh(35);
              right: vw(-12);
              top: vh(24);
              border: 3px solid #2ec7c9;
              border-radius: 3px;
              border-left: none;
            }

            .num {
              color: #fff;
              position: absolute;
              top: 50%;
              left: 50%;
              transform: translate(-50%, -50%);
              z-index: 8;
              font-size: 14px;
              display: flex;

              .font-24 {
                font-size: vw(24);
              }

              .font-28 {
                font-size: vw(28);
                margin-left: 5px;
                font-weight: 600;
              }
            }

            .soc_status {
              border-radius: 2px;
              width: 0;
              height: 100%;
              background-color: rgba(46, 199, 201, 0.25);
            }
          }
        }
      }

      .echartsBox {
        width: 50%;
        height: 140px;
      }
    }

    .StatuAndParamWarp {
      height: 360px;
      width: 100%;
      margin-top: 10px;
      display: flex;
      justify-content: space-between;
      overflow: hidden;

      .statuWarp {
        border-top: 1px solid transparent;
        box-sizing: border-box;
        width: 70%;

        .contentBox {
          display: flex;
          flex-wrap: wrap;
          justify-content: space-between;

          .statusBox {
            width: calc(33.33% - 5px);
            white-space: nowrap;
            text-overflow: ellipsis;
            overflow: hidden;
          }

          .row100 {
            width: calc(66.66% - 2px);
          }
        }
      }

      .paramWarp {
        width: calc(30% - 10px);
      }
    }
  }

  .main_rit {
    width: calc(43% - 10px);
  }
}

.bmsBottom {
  height: calc(100% - 42px - 520px);
  display: flex;
  width: 100%;

  .smallBatterysWarp {
    width: 42%;
    height: 100%;
    border-top: 1px solid transparent;
    box-sizing: border-box;

    .smallBatteryContent {
      display: flex;
      flex-wrap: wrap;
      overflow-y: auto;
      height: calc(100% - 34px);

      .batteryStatuundefined1 {
        flex: 0 0 95px;
        width: 95px;
        height: 32px;
        margin: 2px calc((100% / 6 - 95px) / 2);
        border: 2px solid #c50003;
        position: relative;
        border-radius: 3px;

        .battery-label {
          position: relative;
          z-index: 2;
          text-align: center;
          height: 30px;
          line-height: 30px;
          font-size: 16px;

          .label-index {
            color: #d1d1d1;
            font-size: 12px;
          }

          .volt {
            color: #fff;
            margin: 0 8px 0 3px;
          }
        }

        &::before {
          content: "";
          width: 87px;
          height: 24px;
          background: rgba(255, 0, 0, 0.7);
          position: absolute;
          left: 2px;
          top: 2px;
          border-radius: 1px;
        }

        &::after {
          content: "";
          width: 6px;
          height: 16px;
          border: 2px solid #c50003;
          border-left: none;
          position: absolute;
          right: -7px;
          top: 6px;
          border-radius: 2px;
        }
      }

      .batteryStatuundefined2 {
        flex: 0 0 95px;
        width: 95px;
        height: 32px;
        margin: 2px calc((100% / 6 - 95px) / 2);
        border: 2px solid #de8225;
        position: relative;
        border-radius: 3px;

        .battery-label {
          position: relative;
          z-index: 2;
          text-align: center;
          height: 30px;
          line-height: 30px;
          font-size: 16px;

          .label-index {
            color: #d1d1d1;
            font-size: 12px;
          }

          .volt {
            color: #fff;
            margin: 0 8px 0 3px;
          }
        }

        &::before {
          content: "";
          width: 87px;
          height: 24px;
          background: rgba(255, 165, 0, 0.7);
          position: absolute;
          left: 2px;
          top: 2px;
          border-radius: 1px;
        }

        &::after {
          content: "";
          width: 6px;
          height: 16px;
          border: 2px solid #de8225;
          border-left: none;
          position: absolute;
          right: -7px;
          top: 6px;
          border-radius: 2px;
        }
      }

      .batteryStatuundefined {
        flex: 0 0 95px;
        width: 95px;
        height: 32px;
        margin: 2px calc((100% / 6 - 95px) / 2);
        border: 2px solid #28dede;
        position: relative;
        border-radius: 3px;

        .battery-label {
          position: relative;
          z-index: 2;
          text-align: center;
          height: 30px;
          line-height: 30px;
          font-size: 16px;

          .label-index {
            color: #d1d1d1;
            font-size: 12px;
          }

          .volt {
            color: #fff;
            margin: 0 8px 0 3px;
          }
        }

        &::before {
          content: "";
          width: 87px;
          height: 24px;
          background: rgba(135, 206, 235, 0.7);
          position: absolute;
          left: 2px;
          top: 2px;
          border-radius: 1px;
        }

        &::after {
          content: "";
          width: 6px;
          height: 16px;
          border: 2px solid #28dede;
          border-left: none;
          position: absolute;
          right: -7px;
          top: 6px;
          border-radius: 2px;
        }
      }
    }
  }

  .warnWarp {
    width: 330px;
    height: 100%;
    margin-left: 10px;
    position: relative;

    .contentBox {
      height: calc(100% - 34px);
      overflow-y: auto;
      box-sizing: inherit;

      div {
        width: 100%;
        padding: 4px 4px;
        background: #2d2d2d;
        border-radius: 3px;
        margin-bottom: 6px;
        display: flex;
        justify-content: center;
        font-size: 14px;
        color: #ff455c;

        &:last-child {
          margin-bottom: 0px;
        }
      }
    }

    .noAlarm {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  }

  .boxMap {
    flex: 1;
    height: 100%;
    margin-left: 10px;
    position: relative;

    .address {
      position: absolute;
      display: inline-block;
      background: #062627b3;
      color: #fff;
      z-index: 6;
      width: 100%;
      margin: 0;
      padding: 5px 30px 5px 10px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      font-size: 14px;
      height: 26px;
    }
  }
}

.softStatusColorInfo {
  color: #333;
  position: relative;
  padding-left: 30px;
  margin: 5px 0;

  i {
    width: 24px;
    height: 8px;
    position: absolute;
    left: 0px;
    top: 6px;
    border-radius: 2px;
  }

  &::before {
    content: "";
    display: inline-block;
    width: 30px;
    height: 14px;
    position: absolute;
    left: -3px;
    top: 3px;
    border-radius: 2px;
  }

  &::after {
    content: "";
    position: absolute;
    width: 4px;
    height: 6px;
    left: 25px;
    top: 7px;
  }

  &.ColorInfo1 {
    &::before {
      border: 2px solid #ffa56c;
    }

    &::after {
      background-color: #ffa56c;
    }

    i {
      background: rgba(255, 165, 108, 0.6);
    }
  }

  &.ColorInfo2 {
    &::before {
      border: 2px solid #ef344b;
    }

    &::after {
      background-color: #ef344b;
    }

    i {
      background: rgba(239, 52, 75, 0.6);
    }
  }

  &.ColorInfo3 {
    &::before {
      border: 2px solid #84c565;
    }

    &::after {
      background-color: #84c565;
    }

    i {
      background: #84c56599;
    }
  }

  &.ColorInfo4 {
    &::before {
      border: 2px solid #2e8dc9;
    }

    &::after {
      background-color: #2e8dc9;
    }

    i {
      background: hsla(203, 63%, 48%, 0.6);
    }
  }
}

.warnWarpUl {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;

  li {
    width: 50%;
    color: #333;
  }
}

.dialogUl,
.dialogUlTO {
  display: flex;
  flex-wrap: wrap;

  li {
    width: 50%;
    color: #333;
    margin-top: 10px;

    &.el-col-16 {
      width: 100%;
    }
  }
}

.dialogUlTO {
  li {
    width: 25%;
    color: #333;
    margin-top: 10px;
  }
}

.fontColor_333 {
  :deep(.el-input__inner) {
    color: #333;
  }
}
</style>
<style lang="scss">
.el-popper__arrow:before {
  background: #fff !important;
  border: 1px solid #fff !important;
}

// /* 定制滚动条整体 */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
  background-color: #9d9d9d;
}

/* 定制滚动条轨道 */
::-webkit-scrollbar-track {
  background-color: #f1f1f1;
  /* 轨道颜色 */
}

/* 定制滚动条滑块 */
::-webkit-scrollbar-thumb {
  background-color: #9d9d9d;
  /* 滑块颜色 */
  border-radius: 6px;
  /* 圆角 */
}

/* 滑块在鼠标悬停时改变颜色 */
::-webkit-scrollbar-thumb:hover {
  background-color: #747373;
}
</style>
